/**********************************************************************************
// WindowsGame Header File
//
// Creation:	19 May 2007
// Updated:		04 Jun 2011
// Compiler:	Visual Studio 2010
//
// Notes:	    The class abstracts all the details of setting up a window and 
//				a game loop. The user of the class has to subclass it and 
//				overwrite the methods GameInit, GameLogic, GameDraw and
//				GameShutdown. Creating an object of the subclass and calling 
//              the methods Initialize() and Start() will run the game.
//
//              WindowsGame methods should be invoked only from these overriden 
//				methods, not from the constructor of the game class. That's because 
//				some of the attributes of WindowGame are only set after the 
//				Start() method is called.
**********************************************************************************/

#ifndef _ANABELE_WINDOWSGAME_H_
#define _ANABELE_WINDOWSGAME_H_

#pragma warning (disable: 4251) // string needs dll-interface warnings

/**********************************************************************************/
// Includes

#include <windows.h>	// include important windows stuff
#include <windowsx.h>	// include helpful macros
#include <mmsystem.h>	// include multimedia functions
#include <iostream>		// include important C/C++ stuff
#include <string>		// include string class
#include "Types.h"      // include engine custom types
using std::string;

/**********************************************************************************/

// make classes and functions exportable to a DLL
#ifdef ANABELE_EXPORTS
#define DLL __declspec( dllexport ) 
#else
#define DLL __declspec( dllimport )
#endif

/**********************************************************************************/
// Global Macros and InLine Functions

inline bool KeyDown(int vkcode) // return true if key is down
{ return ((GetAsyncKeyState(vkcode) & 0x8000) ? true : false); }

inline bool KeyUp(int vkcode)   // return true if key is up
{ return ((GetAsyncKeyState(vkcode) & 0x8000) ? false : true); }

/**********************************************************************************/
// Global Constants and Enumerations

enum WindowModes {FULLSCREEN, WINDOWED};

/**********************************************************************************/

class DLL WindowsGame
{
private:

	static HINSTANCE hInstance;		// handle to application instance
	static HWND	windowHandle;		// handle to game window
	static int	windowWidth;		// window width
	static int	windowHeight;		// window height

	HICON		windowIcon;			// handle to game window icon
	HCURSOR		windowCursor;		// handle to game window cursor
	HBRUSH		windowBgColor;		// backgroud color of the game window
	string		windowTitle;		// name of the game window
	DWORD		windowStyle;		// window style
	int			windowMode;			// windowed or fullscreen game
	int			windowPosX;			// initial horizontal window position
	int			windowPosY;			// initial vertical window position
	int			midWindowX;			// middle horizontal position of window
	int			midWindowY;			// middle vertical position of window 
	int			gameWorldWidth;		// game world width
	int			gameWorldHeight;	// game world height
	int			midGameWorldX;		// middle horizontal position of game world
	int			midGameWorldY;		// middle vertical position of game world

	// Protected members are private to the external world but 
	// public to the derived classes. The derived classes of
	// WindowsGame must be able to access these members.

protected:
	// These methods will be overriden in the derived classes.
	// Making them virtual, makes the compiler use dynamic binding, 
	// i.e. the methods of the derived classes will always be 
	// used, even if using a pointer of the base class to point to 
	// an object of the derived class.

	virtual void GameInit();		// game world and objects should be created here
	virtual void GameLogic();		// game logic should be implemented here
	virtual void GameDraw();		// game draw calls should be done here
	virtual void GameShutdown();	// deallocations and shutdown process should be here
 	
public:
	WindowsGame();										// WindowsGame constructor

	static HINSTANCE GetInstance();						// return application instance of the game
	static HWND GetWindowHandle();						// return main window handle of the game
	static int GetWindowWidth(); 						// return current window width
	static int GetWindowHeight(); 						// return current window height

	int  GetMidWindowX() const;							// return horizontal position for the middle of the window
	int  GetMidWindowY() const;							// return vertical position for the middle of the window
	int  GetWindowMode()   const; 						// return current window mode, FULLSCREEN or WINDOWED

	void SetWindowIcon(const HICON icon);				// set the window icon used in the game
	void SetWindowCursor(const HCURSOR cursor);			// set the window cursor used in the game
	void SetWindowTitle(const string title);			// set the window title 
	void SetWindowSize(int width, int height);			// set the window size

	void SetGameWorldSize(int width, int height);		// set the game world size
	int  GetGameWorldWidth() const;						// return current game world width
	int  GetGameWorldHeight() const;					// return current game world height
	int  GetMidGameWorldX() const;						// return horizontal middle position of game world 
	int  GetMidGameWorldY() const;						// return vertical middle position of game world 

	void ShowWindowCursor(bool show);					// enable or disable the cursor 
	void EndsOnEscape();								// quit game by pressing ESC
	void QuitGame();									// quit game

	virtual int Text(char * text, int x, int y, COLORREF color);	// draw text using Windows GDI - slow
	virtual void SetWindowMode(int mode);							// set window mode, FULLSCREEN or WINDOWED
	virtual void SetWindowBgColor(int r, int g, int b);				// set the window background color
	virtual bool Initialize(HINSTANCE appInstance);					// register and create the window
	virtual int Start();											// start the game loop

};

/**********************************************************************************/

// InLine Member Functions

// return main window handle of the game
inline HWND WindowsGame::GetWindowHandle()
{ return windowHandle; }

// return application instance of the game
inline HINSTANCE WindowsGame::GetInstance()
{ return hInstance; }

// return current window width
inline int WindowsGame::GetWindowWidth() 
{ return windowWidth;  }

// return current window height
inline int WindowsGame::GetWindowHeight() 
{ return windowHeight; }

// return horizontal position for the middle of the window
inline int WindowsGame::GetMidWindowX() const
{ return midWindowX; }

// return vertical position for the middle of the window
inline int WindowsGame::GetMidWindowY() const
{ return midWindowY; }


// return current window mode, FULLSCREEN or WINDOWED
inline int WindowsGame::GetWindowMode() const 
{ return windowMode;   }

// return current game world width
inline int WindowsGame::GetGameWorldWidth() const						
{ return gameWorldWidth; }

// return current game world height
inline int WindowsGame::GetGameWorldHeight() const
{ return gameWorldHeight; }

// return horizontal middle position of game world
inline int WindowsGame::GetMidGameWorldX() const
{ return midGameWorldX; }

// return vertical middle position of game world 
inline int WindowsGame::GetMidGameWorldY() const
{ return midGameWorldY; }

// set the window icon used in the game
inline void WindowsGame::SetWindowIcon(const HICON icon)	
{ windowIcon = icon; }

// set the window cursor used in the game
inline void WindowsGame::SetWindowCursor(const HCURSOR cursor)
{ windowCursor = cursor; }

// set the window background color
inline void WindowsGame::SetWindowBgColor(int r, int g, int b)	
{ windowBgColor=(HBRUSH)CreateSolidBrush(RGB(r,g,b)); }

// set the window title 
inline void WindowsGame::SetWindowTitle(const string title)
{ windowTitle = title; }

// enable or disable the cursor 
inline void WindowsGame::ShowWindowCursor(bool show) 
{ ShowCursor(show); }

// quit game by pressing ESC
inline void WindowsGame::EndsOnEscape()
{ if (KeyDown(VK_ESCAPE)) PostMessage(windowHandle, WM_DESTROY,0,0); }

// quit game 
inline void WindowsGame::QuitGame()
{ PostMessage(windowHandle, WM_DESTROY,0,0); }


/**********************************************************************************/

// Global Functions Declaration

// process window messages sent by Windows
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

/**********************************************************************************/

#endif